package grandehealth.AudioVideoSDK.WebRTC;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.telecom.Call;
import android.util.Log;


import com.koushikdutta.async.http.AsyncHttpClient;
import com.koushikdutta.async.http.WebSocket;

import org.apache.http.conn.ssl.SSLSocketFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.SessionDescription;
import org.webrtc.VideoRenderer;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


/**
 * Created by Max on 10-4-2015.
 */
public class WebRtcClient implements AsyncHttpClient.WebSocketConnectCallback, WebSocket.StringCallback {
    private final static String TAG = WebRtcClient.class.getCanonicalName();



    // 呼叫类型
    public  static final int CallTypeForNone = 0;               //  没有呼叫
    public  static final int CallTypeForAudioVideo = 100;       //  呼叫 音视频
    public  static final int CallTypeForAudio = 101;            //  呼叫 音频
    private  static int getCallType = CallTypeForNone;

    public static int getGetCallType() {
        return getCallType;
    }

    public static void setGetCallType(int getCallType) {
        WebRtcClient.getCallType = getCallType;
    }

    public String           currentFrom;                        //  对方用户

    private WebSocket       socket;
    public MyWebRTCApp      webRTCApp;

    public RtcListener      mListener;
    public Context          mContext;

    public WebRtcClient(Context context, RtcListener listener, String host, int width, int height,
                        EglBase.Context renderEGLContext, VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender ) {

        mContext = context;

        webRTCApp = new MyWebRTCApp( this, mContext, width, height , renderEGLContext, localRender, remoteRender );

        mListener = listener;

        AsyncHttpClient client = AsyncHttpClient.getDefaultInstance();

        TrustManager[] byPassTrustManagers = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }
        } };

        SSLContext sslContext=null;
        try {
            sslContext = SSLContext.getInstance("TLS");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        try {
            sslContext.init(null, byPassTrustManagers, new SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        client.getSSLSocketMiddleware().setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        client.getSSLSocketMiddleware().setSSLContext(getSslContext());
        client.getSSLSocketMiddleware().setTrustManagers(byPassTrustManagers);

        client.websocket(host, null, this);

    }

    public void sendMessage(RtcCommandBase message) {
        try {
            sendJsonMessage(message.compile());
        } catch(JSONException jse) {
            Log.e(TAG, jse.getMessage());
        }
    }

    public void sendMessage(String message) {
        try{
            if(socket != null && socket.isOpen()) {
                System.out.println( "socket---==Send---Message: " + message );
                socket.send(message);
            }else{
                System.out.println( "socket---==有问题" );
            }
        } catch(Exception jse) {
            Log.e(TAG, jse.getMessage());
        }
    }

    public void sendJsonMessage(String jsonMsg) {
        System.out.println( "socket---==Send---jsonMsg: " + jsonMsg );
        try{
            if ( socket != null && socket.isOpen() ){
                socket.send( jsonMsg );
            }else{
                System.out.println( "socket---==end---jsonMsg---有问题--socket.isOpen: " + socket.isOpen() );
            }
        } catch(Exception jse) {
            Log.e(TAG, jse.getMessage());
        }
    }

    @Override
    public void onCompleted(Exception ex, WebSocket webSocket) {
        // 完成
        socket = webSocket;
        if (socket != null)
            socket.setStringCallback(this);
        mListener.onSocketCompleted();
    }

    //    @Override
    public void onPingReceived(final String msg) {
        System.out.println("socket---==onPingReceived: " + msg );
    }

    //    @Override
    public void onPongReceived(final String msg) {
        System.out.println("socket---==onPongReceived: " + msg );
    }



    @Override
    public void onStringAvailable(final String s) {

         System.out.println("socket---==接受到的msg: " + s );

//        Log.i(TAG, "socket---==接受到的msg: " + s );

        JSONObject parsedMessage = null;
        try {
            parsedMessage = new JSONObject(s);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (parsedMessage != null) {
            String messageId = "";
            String getResponse = "";

            try {
                if ( parsedMessage.has("id") ){
                    messageId = parsedMessage.getString("id");
                }
                if ( parsedMessage.has("response") ){
                    getResponse = parsedMessage.getString("response");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }

            if ( getResponse.equals("rejected")){
                // 对方 未注册 或 拒绝通信
                if ( getCallType == CallTypeForNone ){
                    return;
                }

                String getMesssage = null;
                if ( parsedMessage.has("message") ){
                    // 对方 拒绝通信
                    try {
                        getMesssage  = parsedMessage.getString("message");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                try {
                    if( getMesssage == null || getMesssage.length() == 0  ){
                        // 对方 拒绝通信
                        mListener.onCallResponseFailed( "对方拒绝接听" );
                    }else{
                        // 对方未注册
                        mListener.onCallResponseFailed( getMesssage );
                    }
                } catch (Exception e) {
                    Log.e( "e.printStackTrace() : ", e + "" );

                    setGetCallType( CallTypeForNone );

                }
                return;
            }


            switch (messageId) {
                case "registerResponse":
                    // 注册 name 后，得到的响应
                    System.out.println("socket---==注册 name 后，得到的响应 : " +  parsedMessage );
                    registerResponse(parsedMessage);
                    break;
                case "appurl":
                    // 注册 name 后，得到appurl
                    Log.i(TAG, "onStringAvailable: ");

                    System.out.println("socket---==ParsedMessage : " +  parsedMessage );
                    break;
                case "incomingCall":
                    incomingCall(parsedMessage);
                    break;
                case "startCommunication":
                    startCommunication(currentFrom ,parsedMessage);
                    break;
                case "stopCommunication":
                    // 停止 视频流 播放
                    stopCommunication();
                    break;
                case "iceCandidate":
                    Log.i(TAG, "iceCandidate");
                    if (parsedMessage != null) {
                        try {
                            JSONObject data = parsedMessage.getJSONObject("candidate");
                            String sdpMid = data.getString("sdpMid");
                            int sdpMLineIndex = data.getInt("sdpMLineIndex");
                            String sdp = data.getString("candidate");
                            IceCandidate candidate = new IceCandidate(sdpMid, sdpMLineIndex, sdp);
                            webRTCApp.nbmWebRTCPeer.addRemoteIceCandidate(candidate, webRTCApp.getConnectionId());
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case "callResponse":
                    // 主动呼叫其他人 ， 获取到其他人的响应
                    if ( getResponse.equals("accepted") ){
                        // 呼叫响应
                        try {
                            SessionDescription sdpAnswer = new SessionDescription(SessionDescription.Type.ANSWER, parsedMessage.getString("sdpAnswer"));
                            webRTCApp.nbmWebRTCPeer.processAnswer( sdpAnswer, webRTCApp.getConnectionId() );
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    break;
                case "webRTCForSend":
                    // 特定信令通道
                    String getContentStr = "";
                    try {
                        getContentStr = parsedMessage.getString("content");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    JSONObject jsonContent = null;
                    try {
                        jsonContent = new JSONObject( getContentStr );
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    String jsonContentType = null;
                    try {
                        jsonContentType = jsonContent.getString("type");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    if ( jsonContentType.equals("typeOtherVideo_for_close") ) {
                        // 关闭 其他人 视频流 的视图

                        // 本地 或 远端的 视频视图 隐藏或显示
                        mListener.onVideoViewHiddenOrShow( false, false );

                    }else if ( jsonContentType.equals( "typeOtherVideo_for_open" ) ){
                        //  其他人视频 打开 -- 执行结束远端 视频流

                        // 本地 或 远端的 视频视图 隐藏或显示
                        mListener.onVideoViewHiddenOrShow( false, true );

                    }else if( jsonContentType.equals( "typeAllVideoView_for_hidden" ) ){
                        // 音频通道时，关闭所有的视频视图

                        // 本地 或 远端的 视频视图 隐藏或显示  -- 暂不处理
//                        mListener.onVideoViewHiddenOrShow( true, false );
//                        mListener.onVideoViewHiddenOrShow( false, false );

                    }else if( jsonContentType.equals( "typeAllVideoView_for_show" ) ){
                        // 音频通道结束后，显示所有的视频视图

                        // 本地 或 远端的 视频视图 隐藏或显示
                        mListener.onVideoViewHiddenOrShow( true, true );
                        mListener.onVideoViewHiddenOrShow( false, true );

                    }else if( jsonContentType.equals( "typeCallFor_AudioAndVideo" ) ){
                        //  收到 呼叫的类型 -- 音视频
                        setGetCallType( CallTypeForAudioVideo );

                        // 处理 视频视图 显示
                        // 本地 或 远端的 视频视图 隐藏或显示
                        mListener.onVideoViewHiddenOrShow( true, true );
                        mListener.onVideoViewHiddenOrShow( false, true );

                    }else if( jsonContentType.equals( "typeCallFor_Audio" ) ){
                        //  收到 呼叫的类型 -- 音频
                        setGetCallType( CallTypeForAudio );

                    }else{

                        System.out.println( "暂无该信令---: " + parsedMessage.toString() );
                    }

                    break;
                default:
                    Log.i(TAG, "socket---==JSON Request not handled: " + s );
                    break;
            }
        } else {
            Log.i(TAG, "Invalid JSON");
        }
    }


    public void handleCallAudioVideo(){
        // 处理 呼叫 音视频
        setGetCallType( CallTypeForAudioVideo );

    }

    public void handleCallAudio(){
        // 处理 呼叫 音频
        setGetCallType( CallTypeForAudio );

    }

    private void sendWebRTCForSend(String typeContent){
        // 发送 特定信令 通道
        try {
            JSONObject jsonMsg = new JSONObject();
            jsonMsg.put("id", "webRTCForSend");
            jsonMsg.put("from", webRTCApp.getConnectionId() );
            jsonMsg.put("to", webRTCApp.getFromUserId() );

            JSONObject jsonContent = new JSONObject();
            jsonContent.put( "type", typeContent );
            jsonMsg.put("content", jsonContent.toString() );

            sendJsonMessage( jsonMsg.toString() );

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    private void setCallTypeAndSendMsg(){
        // 设置 呼叫类型 并通知对方

        if ( getCallType == CallTypeForAudioVideo ){
            // 发送 特定信令 通道
            sendWebRTCForSend( "typeCallFor_AudioAndVideo" );

        }else if ( getCallType == CallTypeForAudio ){
            // 发送 特定信令 通道
            sendWebRTCForSend( "typeCallFor_Audio" );

        }else{
            return;
        }
    }

    private void registerResponse(JSONObject message) {
        // 注册 name 后，得到的响应
        try {
            String response = message.getString("response");
            if (response.equalsIgnoreCase("accepted")) {
                Log.i(TAG, "Register success");

                // 注册用户名成功
                mListener.onRegisterSuccessed();

            } else {
                // 注册用户名失败后
                mListener.onRegisterFailed();
                String errorMessage = !message.getString("message").isEmpty() ? message.getString("message") : "Unknown register rejection reason";
                Log.e("RegisterResponse", errorMessage);
                Log.i(TAG, "Error registering user. See console for further information.");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void callOtherUser( String otherUser){
        // 执行 呼叫其他人
        System.out.println( "socket---==主动呼叫人: " + webRTCApp.getConnectionId() + "---其他人_otherUser: " + otherUser );

        webRTCApp.isCallOtherUser = "isCallOtherUser";
        webRTCApp.setFromUserId( otherUser );

        // 设置 呼叫类型 并通知对方
        setCallTypeAndSendMsg();

        if ( webRTCApp.nbmWebRTCPeer == null ){
            webRTCApp.onNBMWebRTCPeer();
        }

        webRTCApp.nbmWebRTCPeer.generateOffer( webRTCApp.getConnectionId(), true );

    }

    private void incomingCall(JSONObject parsedMessage) {
        // 收到其他人呼叫自己的信令
        // If bussy just reject without disturbing user
        String from = "";
        try {
            from = parsedMessage.getString("from");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if ( getCallType != CallTypeForNone ) {
            // 得到 -- 其他人的呼叫
            mListener.onCallReceived(from);
        } else {
            // 在 音视频通信 或 音频通信 中，告知对方在忙中，拒绝通信。
            sendMessage(new RejectCallCommand(from, RejectCallCommand.USER_BUSY));
        }
    }

    public void acceptCall(){
        // 同意 接听通信

        // 设置 按钮状态
        if ( getCallType == CallTypeForNone ){
            return;
        }else if ( getCallType == CallTypeForAudioVideo ){
            //  设置 按钮状态 -- 音视频
            mListener.onSetBtnCallAudioVideoStatus();
        }else if ( getCallType == CallTypeForAudio ){
            //  设置 按钮状态 -- 音频
            mListener.onSetBtnCallAudioStatus();
        }

        webRTCApp.setConnectionId( webRTCApp.getConnectionId() );
        webRTCApp.setUserId( webRTCApp.getConnectionId() );

        if ( webRTCApp.nbmWebRTCPeer == null ){
            webRTCApp.onNBMWebRTCPeer();
        }

        webRTCApp.nbmWebRTCPeer.generateOffer( webRTCApp.getConnectionId() , true );
    }

    private void startCommunication(String from, JSONObject parsedMessage) {
        // 开始 音视频通信

        Log.i(TAG,"SDP answer received, setting remote description");
        try {
            SessionDescription sdpAnswer = new SessionDescription(SessionDescription.Type.ANSWER, parsedMessage.getString("sdpAnswer"));
            webRTCApp.nbmWebRTCPeer.processAnswer(sdpAnswer, webRTCApp.getConnectionId());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendCallMessage(SessionDescription localSdpOffer) {
        // 发送 call 信令，实施呼叫 -- 得到 本地的 localSdpOffer， 并实现 发起 call 信令
        try {
            JSONObject response = new JSONObject();
            response.put("id", "call");
            response.put("from", webRTCApp.getConnectionId() );
            response.put("to", webRTCApp.getFromUserId() );
            response.put("sdpOffer", localSdpOffer.description);
            sendJsonMessage( response.toString() );
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void switchCamera(){
        // 切换 摄像头
        webRTCApp.nbmWebRTCPeer.switchCameraPosition();
    }

    public void setLocalCameraIsCloseOrOpen(){
        // 本地摄像头 -- 关闭 或 打开
        if ( webRTCApp.nbmWebRTCPeer.videoEnabled() ){
            // 关闭

            // 本地 或 远端的 视频视图 隐藏或显示
            mListener.onVideoViewHiddenOrShow( true, false );

            webRTCApp.nbmWebRTCPeer.enableVideo( false );

            // 发送 特定信令 通道
            sendWebRTCForSend( "typeOtherVideo_for_close" );

        }else{
            // 打开

            // 本地 或 远端的 视频视图 隐藏或显示
            mListener.onVideoViewHiddenOrShow( true, true );

            webRTCApp.nbmWebRTCPeer.enableVideo( true );

            // 发送 特定信令 通道
            sendWebRTCForSend( "typeOtherVideo_for_open" );

        }
    }


    public void sendStopCallAV() {
        // 发送 停止呼叫的信令

        try {
            JSONObject response = new JSONObject();
            response.put("id", "stop");
            sendJsonMessage( response.toString() );

            // 停止 视频流 播放
            stopCommunication();

        } catch (JSONException e) {
            e.printStackTrace();
        }

        if ( getCallType == CallTypeForAudio ){
            // 发送 显示视频视图的信令
            sendWebRTCForSend( "typeAllVideoView_for_show" );
        }
    }


    public void stopCommunication() {

        if ( getCallType == CallTypeForAudio ){
            // 显示 视频视图
            mListener.onVideoViewHiddenOrShow( true, true );
            mListener.onVideoViewHiddenOrShow( false, true );
        }

        // 停止 音视频通信  以及  视频流 播放
        setGetCallType( CallTypeForNone );

        try {

            webRTCApp.nbmWebRTCPeer.enableVideo( false );

            // 移除 视频播放 视图
            mListener.onStopAVPlayView();

            // 关闭 视频流
            webRTCApp.nbmWebRTCPeer.close();

            // 移除 nbmWebRTCPeer
            webRTCApp.nbmWebRTCPeer = null;

            webRTCApp = null;

        }catch ( Exception e ){
            System.out.println( "socket---==Error:" + e );
        }
    }


    public SSLContext getSslContext() {

        TrustManager[] byPassTrustManagers = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }
        } };

        SSLContext sslContext=null;

        try {
            sslContext = SSLContext.getInstance("TLS");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        try {
            sslContext.init(null, byPassTrustManagers, new SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        return sslContext;
    }
}
